package org.potomak.patientmanager.persistence;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
import java.util.Iterator;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.potomak.patientmanager.beans.model.CheckUpBean;
import org.potomak.patientmanager.beans.model.PatientBean;

public class JPoxJDO {

    private static final String JPOX_CONFIG = "jpox.properties";
    private static Properties prop;
    private static String key;
    private boolean isInitialized = false;
    private PersistenceManager pm;

    public JPoxJDO(String key) {
        JPoxJDO.key = key;

        if (isInitialized) {
            return;
        } else {
            initialize();
        }
    }

    private void initialize() {
        System.out.println("JpoxJDO, initialize called");
        getDatasourceProps();
        prop.setProperty("javax.jdo.option.ConnectionURL", prop.getProperty("javax.jdo.option.ConnectionURL") + key);
        pm = createPersistenceManager();
        isInitialized = true;
        return;
    }

    public PersistenceManager getPersistenceManager() {
        return pm;
    }

    // load all of the various JPOX properties from a properties file
    private void getDatasourceProps() {
        InputStream is = this.getClass().getResourceAsStream(JPOX_CONFIG);

        prop = new Properties();
        try {
            prop.load(is);
        } catch (IOException exception) {
            throw new RuntimeException("jpox.properties not found.", exception);
        }
    }

    // create the PersistenceManager using the JDO Helper class
    // the persistencemanage is used for all JPOX transactions
    private static PersistenceManager createPersistenceManager() {

        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(prop);

        return pmf.getPersistenceManager();

    }

    // close the persistence manager.
    public void shutdown() {
        if (pm != null) {
            pm.close();
        }

    }

    // If the username is in the APP.PATIENT table retrieve
    // the database row, which in JPOX is the class PatientBean
    public PatientBean getPatient(String patientName) {

        PatientBean patientBean;

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();
            // this represents the query:
            // select username, password from APP.USERS where username = ?
            Query query = pm.newQuery(PatientBean.class, "patientName == name");
            query.declareParameters("String patientName");
            query.setUnique(true);
            patientBean = (PatientBean) query.execute(patientName.trim());
            pm.retrieve(patientBean);
            if (patientBean == null) {
                patientBean = new PatientBean();
            }
            txn.commit();
        } finally {
            if (txn.isActive()) {
                txn.rollback();
            }
        }
        return patientBean;
    }

    // Insert a row into the APP.PATIENT table by first creating a
    // PatientBean, then using JPOX to persist the PatientBean to Derby.
    public boolean insertPatient(String name, Date birthDay, String gender, Double height, Date date) {

        boolean success = false;

        PatientBean patientBean = new PatientBean(name.trim(), birthDay, gender.trim(), height, "notes", date, new HashSet(), new HashSet());

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();
            // I have to have this, otherwise it is not persistent
            pm.makePersistent(patientBean);

            txn.commit();
            success = true;
        } catch(Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }

        return success;
    }

    public boolean insertCheckUp(CheckUpBean checkUp) {
        boolean success = false;

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();
            
            checkUp.getPatient().getCheckUps().add(checkUp);

            txn.commit();
            success = true;
        } catch(Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }

        return success;
    }

    public PatientBean[] patientList() {

        PatientBean[] patientBean = null;
        ListIterator iterator;

        Transaction txn = pm.currentTransaction();
        try {

            txn.begin();

            Query query = pm.newQuery(PatientBean.class);
            query.setClass(PatientBean.class);
            List list = (List) query.execute();

            iterator = list.listIterator();

            if (list.size() > 0) {
                patientBean = new PatientBean[list.size()];
            } else {
                patientBean = new PatientBean[0];
            }

            int i = 0;
            while (iterator.hasNext()) {
                patientBean[i++] = (PatientBean) iterator.next();
            }

            txn.commit();
        } catch(Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
            }

        }

        return patientBean;
    }

    public boolean updatePatient(PatientBean patient, String name, Date birthday, String gender, Double height) {
        boolean success = false;

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();

            Object id = pm.getObjectId(patient);
            System.out.println("searching element id " + id);
            PatientBean patientBean = (PatientBean) pm.getObjectById(id);
            patientBean.setName(name);
            patientBean.setBirthDay(birthday);
            patientBean.setGender(gender);
            patientBean.setHeight(height);

            txn.commit();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }

        return success;
    }

    public boolean updateNotes(PatientBean patient, String notes) {
        boolean success = false;

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();

            patient.setNotes(notes);

            txn.commit();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }

        return success;
    }

    public boolean removePatient(PatientBean patient) {
        boolean success = false;

        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();

            Object id = pm.getObjectId(patient);
            System.out.println("searching element id " + id);
            PatientBean patientBean = (PatientBean) pm.getObjectById(id);
            pm.deletePersistent(patientBean);

            txn.commit();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }
        return success;

    }

    public boolean removeCheckUp(PatientBean patient, CheckUpBean checkUp) {
        boolean success = false;
        
        Transaction txn = pm.currentTransaction();
        try {
            txn.begin();

            System.out.println("Does patient own this check up? " + patient.getCheckUps().contains(checkUp));
            Iterator i = patient.getCheckUps().iterator();

            int num = 0;
            while (i.hasNext()) {
                num++;
                CheckUpBean cub = (CheckUpBean) i.next();

                System.out.println("confronto #" + num + " =>\n" + cub + "\n == \n" + checkUp + " ?? ==>" + cub.equals(checkUp) + "\n\n");

                if (cub.equals(checkUp)) {
                    pm.deletePersistent(cub);
                }
            }

            txn.commit();
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        } finally {
            if (txn.isActive()) {
                txn.rollback();
                success = false;
            }
        }
        
        return success;
    }
}
